package bliVideo
/**
 * 28-什么是lambda https://www.bilibili.com/video/BV1wf4y1s7TG?p=28
 * 我们将匿名函数称为lambda，将它的定义称为lambda表达式，它返回的数据称为lambda结果。
 * 为什么叫lambda? lambda也可以用希腊字符λ表示，是lambda演算的简称，lambda演算是一套数理演算逻辑，
 * 由数学家Alonzo Church (阿隆佐.丘齐)于20世纪30年代发明，在定义匿名函数时，使用了lambda演算记法。
 */


/**
 * 29-定义参数是函数的函数
 */
fun main31() {
    fun setOnListener(goodName: String, listener: (String, Int) -> String) {
        val times = (1..24).shuffled()   //shuffle v/n.洗牌, 拖着走
        val lastTime = times.last()
        println(listener(goodName, lastTime)) //监听回调
    }
    //1.函数的参数是另外一个"匿名函数"
    val getListener: (goodName: String, hour: Int) -> String = { goodName, hour ->
        "双11 $goodName 促销倒计时: $hour 小时"
    }
    setOnListener("香蕉", getListener)


    //30-简略写法
    setOnListener("卫生纸", { goodName, hour ->
        "双11 $goodName 促销倒计时: $hour 小时"
    })
    //if 函数的最后1个参数是Lambda表达式, 则括住Lambda值参的 ) 可省略
    setOnListener("手机") { goodName, hour ->
        "双11 $goodName 促销倒计时: $hour 小时"
    }
}


/**
 * 31-函数内联 (将 inline 里的方法体, 复制进 调用函数)
 */
private inline fun setOnListener(goodName: String, listener: (String, Int) -> String) {
    val times = (1..24).shuffled()   //shuffle v/n.洗牌, 拖着走
    val lastTime = times.last()
    println(listener(goodName, lastTime)) //监听回调
}
fun main32() {
    //1.lambda可以让你更灵活地编写应用，但是，灵活也是要付出代价的。
    //2.在JVM上，你定义的lambda会以对象实例的形式存在，JVM会为所有同lambda打交道的变量分配内存，这就产生了内存开销。
    //  更糟的是，lambda的内存开销会带来严重的性能问题。
    //  幸运的是，kotlin有一种优化机制叫内联，有了内联，JVM就不需要使用lamba对象实例了，因而避免了变量内存分配。
    //  哪里需要使用lambda，编译器就会将函数体复制粘贴到哪里。
    //3.使用lambda的 递归函数无法内联，因为会导致复制粘贴无限循环，编译会发出警告。
    setOnListener("袜子") { goodName, hour ->
        "双11 $goodName 促销倒计时: $hour 小时"
    }
}


/**
 * 32-函数引用 ::getListener
 */
fun main33() {
    //要把函数作为参数传给其他函数使用，除了传lambda表达式，kotlin还提供了其他方法，
    //传递函数引用，函数引用可以把一个具名函数转换成一个值参，使用lambda表达式的地方，都可以使用函数引用。
    fun setOnListener(goodName: String, listener: (String, Int) -> String) {
        val times = (1..24).shuffled()   //shuffle v/n.洗牌, 拖着走
        val lastTime = times.last()
        println(listener(goodName, lastTime)) //监听回调
    }
    fun getListener(goodName: String, hour: Int): String {
        return "双11 $goodName 促销倒计时: $hour 小时"
    }
    setOnListener("牙膏", ::getListener)
}


/**
 * 33-函数类型作为返回类型
 */
fun main34() {
    fun configDiscountWords(): (String) -> String {
        val hour = (1..24).shuffled().last()
        return { goodsName: String ->
            "双11 ${goodsName} 促销倒计时: $hour 小时"
        }
    }
    val getDiscountWords =  configDiscountWords()   //返回1个函数
    println(getDiscountWords("牙膏"))               //调用这个函数, 返回String

    println(configDiscountWords()("沐浴露"))        //简写
}


/**
 * 34-闭包 (Closure)
 * 1.在Kotlin中，匿名函数能修改并引用定义在自己的作用域之外的变量，
 *   匿名函数引用着定义自身的函数里的变量，Kotlin中的lambda就是闭包。
 * 2.能接收函数或者返回函数的函数又叫做"高级函数"，高级函数广泛应用于函数式编程当中。
 */


/**
 * 35-lambda与匿名内部类
 * 1.为什么要在代码中使用函数类型?函数类型能让开发者少写模式化代码，写出更灵活的代码。
 *   Java 8支持面向对象编程和lambda表达式，但不支持将函数作为参数传给另一个函数或变量，不过Java的替代方案是匿名内部类。
 */
